package com.qin.controller;

import java.io.IOException;
import java.sql.SQLException;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.qin.entity.Book;
import com.qin.entity.BookCategory;
import com.qin.entity.Press;
import com.qin.service.BookCategoryService;
import com.qin.service.BookService;
import com.qin.service.impl.BookCategoryServiceImpl;
import com.qin.service.impl.BookServiceImpl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.db.Db;
import cn.hutool.db.Entity;
import cn.hutool.db.handler.BeanHandler;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import cn.hutool.log.StaticLog;
import lombok.Data;

/**
 * 处理发的ajax请求，拿到price或press后author的信息
 */
@WebServlet("/getDataByPriceOrPressOrAuthor")
public class GetDataByPriceOrPressOrAuthorServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
	private BookService bookService = new BookServiceImpl();
	private BookCategoryService bookCategoryService = new BookCategoryServiceImpl();
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String categoryId = request.getParameter("categoryId");
		String queryArgument = request.getParameter("queryArgument");
		String sortStyle = request.getParameter("sortStyle");
		// 尝试获取左值和右值
		String leftV = request.getParameter("leftV");
		String rightV = request.getParameter("rightV");
		StaticLog.debug("对价格过滤的左值：{}和右值：{}", leftV,rightV);
		
		// 获取要求第几页数据
		String skip = request.getParameter("skip");
		long skipNum = Long.parseLong(skip) * 10;
		
		// 得到过滤后的book
		List<Book> booksByArgument = getDataByPriceOrPressOrAuthorServlet(categoryId,queryArgument);
		
		// 对得到的book再继续过滤（判断左值和右值）操作
		List<Book> booksByArgumentAndLeftOrRight = booksByArgument.stream().filter(book->{
			// 先拿到图书的真正价格
			Double price = book.getPrice() * book.getDiscount() / 10;
			
			if(!StrUtil.isEmpty(leftV)) {
				// 左值不为空，则进行过滤，先转数字
				double parseInt = Double.parseDouble(leftV);
				// 进行过滤
				return price >= parseInt;
			}
			
			if(!StrUtil.isEmpty(rightV)) {
				// 右值不为空，则进行过滤，先转数字
				double parseInt = Double.parseDouble(rightV);
				// 进行过滤
				return price <= parseInt;
			}
			
			return true;
		}).collect(Collectors.toList());
		
		// 得到book的总量
		int num = booksByArgument.size();
		
		List<Book> collect = null;
		
		// 进行排序后只要前十条数据
		if(StrUtil.equals(sortStyle, "normal")) { // 正常：打乱
			Collections.shuffle(booksByArgumentAndLeftOrRight);
			collect = booksByArgumentAndLeftOrRight.stream().skip(skipNum).limit(10).collect(Collectors.toList());
		}else if(StrUtil.equals(sortStyle, "sales")) { // 按照销量从高到低
			collect = booksByArgumentAndLeftOrRight.stream().skip(skipNum).limit(10).sorted(Comparator.comparing(Book::getSales).reversed()).collect(Collectors.toList());
		}else if(StrUtil.equals(sortStyle, "createTime")) { // 按照出版时间从近到远
			collect = booksByArgumentAndLeftOrRight.stream().skip(skipNum).limit(10).sorted(Comparator.comparing(Book::getCreateTime).reversed()).collect(Collectors.toList());
		}else if(StrUtil.equals(sortStyle, "price")) { // 按照价格由低到高
			collect = booksByArgumentAndLeftOrRight.stream().skip(skipNum).limit(10).sorted(Comparator.comparing(Book::getPrice)).collect(Collectors.toList());
		}else if(StrUtil.equals(sortStyle, "rprice")) { // 按照价格由高到底
			collect = booksByArgumentAndLeftOrRight.stream().skip(skipNum).limit(10).sorted(Comparator.comparing(Book::getPrice).reversed()).collect(Collectors.toList());
		}else {	// 这里是好评，不做处理
			collect = booksByArgumentAndLeftOrRight.stream().skip(skipNum).limit(10).collect(Collectors.toList());
		}
		
		// 准备一个map，把总数和数量放进去
		Map<Integer,List<Book>> map = new HashMap<>();
		map.put(num, collect);
		
		// 把list转成json并返回
		String jsonStr = JSONUtil.toJsonStr(map);
		response.getWriter().print(jsonStr);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doGet(request, response);
	}
	
	/**
	 * 根据请求过滤参数，得到过滤后的books
	 * @param id （请求域中）图书分类的id
	 * @param queryArgument （前端发过来的JSON格式，请求参数）
	 * @return booksByArgument 过滤后的books
	 */
	public List<Book> getDataByPriceOrPressOrAuthorServlet(String id,String queryArgument){
		// 准备一个map，用来放请求参数数据
				Map<String,String> arguments = new HashMap<>();
				// 拿到JSON对象数组
				JSONArray parseArray = JSONUtil.parseArray(queryArgument);
				// 遍历这个JSON对象数组
				for (int i = 0; i < parseArray.size(); i++) {
					Argument arg = parseArray.get(i, Argument.class);
					System.out.println("parseArray:"+parseArray+"arg:"+arg);
					// 把要得到的key和value放进去
					arguments.put(arg.getKey(),arg.getValue());
				}
				
				StaticLog.debug("参数过滤Map：{}", arguments);
				
				// 拿到分类id，判断是二级分类还是一级分类
				long parseLong = Long.parseLong(id);
				BookCategory bookCategoryById = bookCategoryService.getBookCategoryById(parseLong);
				
				List<Book> booksByArgument = null;
				if(bookCategoryById.getCatLevel() == 2) {
					// 如果是二级分类
					List<Book> booksByCategoryLevel2Id = bookService.getBooksByCategoryLevel2Id(parseLong);
					
					if(booksByCategoryLevel2Id != null) {
						// 得到过滤后的图书
						booksByArgument = getBooksByArgument(booksByCategoryLevel2Id,arguments);
						
					}
				}else{
					// 如果是三级分类
					List<Book> booksByCategoryLevel3Id = bookService.getBooksByCategoryLevel3Id(parseLong);

					if(booksByCategoryLevel3Id != null) {
						// 得到过滤后的图书
						booksByArgument = getBooksByArgument(booksByCategoryLevel3Id,arguments);
					}
				
				}
				
				return booksByArgument;
	}
	
	/**
	 * 给定一个字符串（不能为空），尽可能转成数字（前面一定有数字）
	 * 比如："123eawr" => "123"
	 * @param str 
	 * @return 数字
	 */
	private static int stringToInt(String str) {
		// 拿到这个字符串的长度，进行遍历
		int length = str.length();
		
		// 记录数字最后的下标
		int index = 0;
		for (int i = 0; i < length; i++) {
			char charAt = str.charAt(i);
			if(Character.isDigit(charAt)) {
				index++;
			}else {
				break;
			}
		}
		
		// 最后截取对应的长度并转成数字返回
		return Integer.parseInt(StrUtil.subWithLength(str, 0, index));
	}

	/**
	 * 给一个图书集合和一个过滤Map进行过滤
	 * @param books
	 * @param arguments 过滤条件的map
	 * @return 过滤后的List<Book>
	 */
	private List<Book> getBooksByArgument(List<Book> books,Map<String,String> arguments) {
		return books.stream().filter(book->{
			// 先处理出版社
			Long pressId = book.getPressId();
			// 拿到出版社
			Press find = null;
			try {
				find = Db.use().find(Entity.create("press").set("id", pressId), new BeanHandler<Press>(Press.class));
			} catch (SQLException e) {
				e.printStackTrace();
			}
			// 还要设置出版社的名字
			book.setPressName( find.getName());
			
			// 如果map中有press
			if(arguments.containsKey("press")) {
				
				// 如果和对应的出版社名字不相等，则过滤
				if(!StrUtil.equalsIgnoreCase(arguments.get("press"), find.getName())) {
					return false;
				}
			}
			
			return true;
		}).filter(book->{
			// 如果map中有author
			if(arguments.containsKey("author")) {
				// 如果和书中的作者名字不相等，则过滤
				String author = book.getAuthor();
				String[] split = author.split(";");
				if(!StrUtil.equalsAny(arguments.get("author"), split)) {
					return false;
				}
			}
			return true;
		}).filter(book->{
			// 如果map中有价格
			if(arguments.containsKey("price")) {
				// 得到真正的价格
				Double nowPrice =  book.getPrice() * book.getDiscount() / 10;
				
				// 先得到价格区间
				String str = arguments.get("price");
				if(str.contains("-")) {
					// 如果有-，则代表是价格区间，先进行分割
					int[] splitToInt = StrUtil.splitToInt(str, "-");
					// 判断价格是否在那个区间内
					return nowPrice >= splitToInt[0] && nowPrice <= splitToInt[1];
					
				}else {
					// 如果没有-，但又包含了price，那应该是在某个区间以上
					// 需要把有数字的部分转成数字
					int stringToInt = stringToInt(str);
					return nowPrice > stringToInt;
				}
			}
			
			return true;
		}).collect(Collectors.toList());
	}
}
@Data
class Argument{
	private String key;
	private String value;
}